/**
  ******************************************************************************
  * @author     Chris
  * @since      2023/10/11 13:57
  *
  * @file       pd_s_spi.c
  * @brief      Simulated of SPI Peripheral Driver .
  *
  * @note       This file contains the simulated peripheral driver for the SPI.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2023/10/11     Chris        the first version
  *
  ******************************************************************************
  */
#include "pd_s_spi.h"
#include "stm32g4xx.h"
#include "stm32g4xx_ll_bus.h"
#include "stm32g4xx_ll_gpio.h"

/** region Declaration and Definition Region */

/** region Variables and Constants Region */

/** endregion */

/** region Function Declaration Region */

void SPI1_CS(uint8_t bitVal, uint8_t pin);

void SPI1_SCK(uint8_t bitVal);

uint8_t SPI1_MISO(void);

void SPI1_MOSI(uint8_t bitVal);

/** endregion */

/** endregion */


/** region Public Definition Region */


/**
 * @brief   软件模拟 SPI1 驱动初始化
 *
 * @note    硬件 SPI 所在引脚：
 *          SPI1_NSS  PA4/PA15(AF4)，PA4 已经被 NRF_CS 占用
 *          SPI1_SCK  PA5/PB3(AF4)
 *          SPI1_MISO PA6/PB4(AF4)
 *          SPI1_MOSI PA7/PB5(AF4)
 *
 * @param   无
 * @retval  无
 */
void PD_S_SPI1_Init(void) {
    // 开启时钟
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
    // 推挽输出
    LL_GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | LL_GPIO_PIN_7 | LL_GPIO_PIN_15;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    // 上拉输入
    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // SPI 通信线初始化
    SPI1_CS(1, SPI1_NSS_NRF24L01);
    SPI1_CS(1, SPI1_NSS_W25QXX);
    SPI1_SCK(0);    // 模式 0：CPOL=0，CPHA=0
}

/**
 * @brief   软件模拟 SPI1 起始条件
 *
 * @note    片选使能
 * @param   无
 * @retval  无
 */
void PD_S_SPI1_Start(uint8_t pin) {
    SPI1_CS(0, pin);
}

/**
 * @brief   软件模拟 SPI1 终止条件
 *
 * @note    片选使能
 * @param   无
 * @retval  无
 */
void PD_S_SPI1_Stop(uint8_t pin) {
    SPI1_CS(1, pin);
}

/**
 * @brief   软件模拟 SPI1 交换一个字节数据
 *
 * @note    模式 0：CPOL=0，CPHA=0
 * @param   dat 待发送的一个字节
 * @retval  接收到的一个字节
 */
uint8_t PD_S_SPI1_SwapByte(uint8_t dat) {
    for (int i = 0; i < 8; ++i) {
        SPI1_MOSI(dat & 0x80);
        dat <<= 1;
        SPI1_SCK(1);
        if (SPI1_MISO()) dat |= 0x01;
        SPI1_SCK(0);
    }
    return dat;
}

/** endregion */


/** region Private Definition Region */

void SPI1_CS(uint8_t bitVal, uint8_t pin) {
    if (bitVal == 0) {
        switch (pin) {
            case 0:
                GPIOA->BRR = LL_GPIO_PIN_4;
                break;
            case 1:
                GPIOA->BRR = LL_GPIO_PIN_15;
                break;
            default:
                break;
        }
    } else {
        switch (pin) {
            case 0:
                GPIOA->BSRR = LL_GPIO_PIN_4;
                break;
            case 1:
                GPIOA->BSRR = LL_GPIO_PIN_15;
                break;
            default:
                break;
        }
    }
}

void SPI1_SCK(uint8_t bitVal) {
    if (bitVal == 0) {
        GPIOA->BRR = LL_GPIO_PIN_5;
    } else {
        GPIOA->BSRR = LL_GPIO_PIN_5;
    }
}

uint8_t SPI1_MISO(void) {
    return (LL_GPIO_ReadInputPort(GPIOA) & (1 << 6)) ? 1 : 0;
}

void SPI1_MOSI(uint8_t bitVal) {
    if (bitVal == 0) {
        GPIOA->BRR = LL_GPIO_PIN_7;
    } else {
        GPIOA->BSRR = LL_GPIO_PIN_7;
    }
}

/** endregion */
